package com.example.im.netty;

import com.example.im.model.Group;
import com.example.im.model.Message;
import com.example.im.service.GroupService;
import com.example.im.service.MessageService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.Setter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.logging.Logger;
import java.util.stream.Collectors;

@Slf4j
public class WebSocketServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private static final int MAX_GROUPS = 10;
    private static final String DEFAULT_GROUP = "G00001";

    private static final Map<String, Map<String, Channel>> groupChannels = new ConcurrentHashMap<>();
    private static final Map<Channel, UserInfo> channelInfo = new ConcurrentHashMap<>();
    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final Map<String, Set<String>> groupUsers = new ConcurrentHashMap<>();
    // 暂时离线用户列表 4.22加
    private static final Map<String, Set<String>> groupOfflineUsers = new ConcurrentHashMap<>();

    private Logger logger = Logger.getLogger(this.getClass().getName());

    @Setter
    private static MessageService messageService; // 用于持久化消息的服务
    @Setter
    private static GroupService groupService;// 用于持久化群组的服务

    //新增：心跳机制
    // 心跳超时时间（毫秒）
    private static final long HEARTBEAT_TIMEOUT = 30000; // 5分钟（300秒）
    // 心跳间隔（毫秒）
    private static final long HEARTBEAT_INTERVAL = 1000; // 1秒

    @PostConstruct
    public void init() {
        // 在静态初始化块中创建默认群组
        groupChannels.put(DEFAULT_GROUP, new ConcurrentHashMap<>());
        groupUsers.put(DEFAULT_GROUP, ConcurrentHashMap.newKeySet());

        List<Group> groups = groupService.getAllGroups();
        logger.info("群聊为："+groups);
        for (Group group : groups) {
            groupChannels.put(group.getGroup_id(), new ConcurrentHashMap<>());
            groupUsers.put(group.getGroup_id(), ConcurrentHashMap.newKeySet());
        }
        log.info("Created default group: {}", DEFAULT_GROUP);
    }


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws Exception {
        String text = frame.text();
        logger.info("初始化群聊："+groupChannels);


        logger.info("init证明："+groupChannels);
        // 处理心跳消息
        if ("HEARTBEAT".equals(text)) {
            log.debug("Received heartbeat from {}", ctx.channel().id());
            return; // 直接返回，不进行JSON解析
        }

        // 消息处理逻辑
        Message message = objectMapper.readValue(text, Message.class);

        //4.22新增26
        UserInfo userInfo = channelInfo.get(ctx.channel());
        // 如果用户存在于离线列表，则恢复在线状态
        if (userInfo != null) {
            /*Set<String> offlineUsers = groupOfflineUsers.get(userInfo.groupId);
            if (offlineUsers != null && offlineUsers.remove(userInfo.userId)) {
                groupUsers.computeIfAbsent(userInfo.groupId, k -> ConcurrentHashMap.newKeySet())
                        .add(userInfo.userId);
                broadcastOnlineUsers(userInfo.groupId);
                broadcastOfflineUsers(userInfo.groupId);
            }*/
            Set<String> offlineUsers = groupOfflineUsers.get(userInfo.groupId);
            if (offlineUsers != null && offlineUsers.remove(userInfo.userId)) {
                // 如果离线用户列表为空，则从map中移除该群组的记录
                if (offlineUsers.isEmpty()) {
                    groupOfflineUsers.remove(userInfo.groupId);
                }
                groupUsers.computeIfAbsent(userInfo.groupId, k -> ConcurrentHashMap.newKeySet())
                        .add(userInfo.userId);
                broadcastOnlineUsers(userInfo.groupId);
                broadcastOfflineUsers(userInfo.groupId); // 确保调用这个方法来更新离线列表
            }
        }


        // 如果是加入群组的消息
        if (message.getContent() != null && message.getContent().startsWith("JOIN_GROUP:")) {
            logger.info(message.getContent());
            String groupId = message.getContent().substring("JOIN_GROUP:".length());
            // 如果是创建新群组（不是加入默认群组）且已达到上限，则拒绝
            if (!DEFAULT_GROUP.equals(groupId) &&
                    !groupChannels.containsKey(groupId) &&
                    groupChannels.size() >= MAX_GROUPS) {

                // 发送错误消息给客户端
                Message errorMessage = new Message();
                errorMessage.setFromUser("system");
                errorMessage.setContent("ERROR:MAX_GROUPS_REACHED");
                errorMessage.setGroupId(groupId);
                errorMessage.setTimestamp(System.currentTimeMillis());
                ctx.channel().writeAndFlush(new TextWebSocketFrame(objectMapper.writeValueAsString(errorMessage)));
                return;
            }
            //将新创建的聊天群保存到数据库
            logger.info("当前操作的群"+groupId);
            logger.info("全部群聊："+groupService.getAllGroups());
            boolean flag=false;
            for (int i = 0; i < groupService.getAllGroups().size(); i++) {
                if(groupId.equalsIgnoreCase(groupService.getAllGroups().get(i).getGroup_id()))
                {
                    flag=true;
                }
            }
            if(!groupChannels.containsKey(groupId)&&!"G00001".equals(groupId)&&!flag){
                Group group = new Group();
                group.setGroup_id(groupId);
                group.setGroup_owner(message.getFromUser());
                group.setGroup_user(message.getFromUser());
                groupService.createGroup(group);
            }
            // 添加用户到群组
            addUserToGroup(groupId, message.getFromUser(), ctx.channel());
            channelInfo.put(ctx.channel(), new UserInfo(message.getFromUser(), groupId));

            // 添加用户到群组用户集合
            groupUsers.computeIfAbsent(groupId, k -> ConcurrentHashMap.newKeySet()).add(message.getFromUser());
            //用户入群持久化
            if(!DEFAULT_GROUP.equals(groupId)) {
                log.info("加入的组号:"+groupId);
                groupService.joinGroup(groupId,message.getFromUser());
            }
            // 广播在线用户列表更新
            broadcastOnlineUsers(groupId);

            log.info("User {} joined group {}", message.getFromUser(), groupId);
            return;
        }

        // 广播消息
        Map<String, Channel> channels = groupChannels.get(message.getGroupId());
        if (channels != null) {
            String messageJson = objectMapper.writeValueAsString(message);
            channels.values().forEach(channel ->
                    channel.writeAndFlush(new TextWebSocketFrame(messageJson))
            );
            log.info("Message broadcast to group {}: {}", message.getGroupId(), messageJson);


            // 保存消息到数据库
            if (messageService != null) {
                messageService.saveMessage(message);
            }

        }
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        log.info("Handler Added: {}", ctx.channel().id());

        //新增：心跳机制
        // 启动心跳
        sendHeartbeat(ctx);
        // 设置读空闲检测
        ctx.channel().config().setOption(ChannelOption.SO_KEEPALIVE, true);
        ctx.pipeline().addBefore(ctx.name(), "idleStateHandler",
                new IdleStateHandler(HEARTBEAT_TIMEOUT, 0, 0, TimeUnit.MILLISECONDS));
    }

    /*@Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        log.info("Handler Removed: {}", ctx.channel().id());
        UserInfo userInfo = channelInfo.remove(ctx.channel());
        if (userInfo != null) {
            Map<String, Channel> groupChannelMap = groupChannels.get(userInfo.groupId);
            if (groupChannelMap != null) {
                groupChannelMap.remove(userInfo.userId);
                if (groupChannelMap.isEmpty()) {
                    groupChannels.remove(userInfo.groupId);
                }
            }

            // 从在线用户列表中移除
            Set<String> onlineUsers = groupUsers.get(userInfo.groupId);
            if (onlineUsers != null) {
                onlineUsers.remove(userInfo.userId);
                broadcastOnlineUsers(userInfo.groupId);
            }


            log.info("User {} removed from group {}", userInfo.userId, userInfo.groupId);
        }
    }*/
    //4.23新增2
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        log.info("Handler Removed: {}", ctx.channel().id());
        UserInfo userInfo = channelInfo.remove(ctx.channel());
        if (userInfo != null) {
            // 获取用户加入的所有群组
            Set<String> userGroups = new HashSet<>();
            for (Map.Entry<String, Map<String, Channel>> entry : groupChannels.entrySet()) {
                if (entry.getValue().containsKey(userInfo.userId)) {
                    userGroups.add(entry.getKey());
                }
            }

            // 在所有群组中移除用户
            for (String groupId : userGroups) {
                // 从通道映射中移除
                Map<String, Channel> groupChannelMap = groupChannels.get(groupId);
                if (groupChannelMap != null) {
                    groupChannelMap.remove(userInfo.userId);
                    if (groupChannelMap.isEmpty()) {
                        groupChannels.remove(groupId);
                    }
                }

                // 从在线/离线列表中移除
                Set<String> onlineUsers = groupUsers.get(groupId);
                if (onlineUsers != null) {
                    onlineUsers.remove(userInfo.userId);
                }
                Set<String> offlineUsers = groupOfflineUsers.get(groupId);
                if (offlineUsers != null) {
                    offlineUsers.remove(userInfo.userId);
                }

                // 广播更新
                broadcastOnlineUsers(groupId);
                broadcastOfflineUsers(groupId);
            }

            log.info("User {} removed from all groups", userInfo.userId);
        }
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("WebSocket Error: ", cause);
        ctx.close();
    }

    // 添加用户到群组
    public static void addUserToGroup(String groupId, String userId, Channel channel) {
        groupChannels.computeIfAbsent(groupId, k -> new ConcurrentHashMap<>())
                .put(userId, channel);
    }

    // 获取所有群组ID
    public static Set<String> getAllGroupIds(String user) {
        Set<String> allGroups = new LinkedHashSet<>();
        allGroups.add(DEFAULT_GROUP); // 确保默认群组在第一位
        allGroups.addAll(groupChannels.keySet().stream()
                .filter(id -> !id.equals(DEFAULT_GROUP))
                .collect(Collectors.toSet()));
        return allGroups;

    }

    /*//获取当前用户加入的群组
    public static Set<Group> getGroupIdsByUser(String userId) {
        Set<String> allGroupsByUser = new LinkedHashSet<>();
        allGroupsByUser.add(DEFAULT_GROUP);
        allGroupsByUser.addAll(groupChannels.get(userId).keySet());

    }*/

    // 添加广播在线用户列表的方法
    private void broadcastOnlineUsers(String groupId) {
        try {
            Set<String> users = groupUsers.get(groupId);
            if (users != null) {
                Message userListMessage = new Message();
                userListMessage.setFromUser("system");
                userListMessage.setGroupId(groupId);
                userListMessage.setContent("ONLINE_USERS:" + String.join(",", users));
                userListMessage.setTimestamp(System.currentTimeMillis());

                String messageJson = objectMapper.writeValueAsString(userListMessage);
                Map<String, Channel> channels = groupChannels.get(groupId);
                if (channels != null) {
                    channels.values().forEach(channel ->
                            channel.writeAndFlush(new TextWebSocketFrame(messageJson))
                    );
                }
                log.debug("Broadcasted online users for group {}: {}", groupId, users);
            }
        } catch (Exception e) {
            log.error("Error broadcasting online users for group " + groupId, e);
        }
    }

    // 用于存储Channel关联的用户信息
    private static class UserInfo {
        String userId;
        String groupId;

        UserInfo(String userId, String groupId) {
            this.userId = userId;
            this.groupId = groupId;
        }
    }


    //新增：心跳机制
    // 添加心跳检测逻辑
    /*@Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            if (e.state() == IdleState.READER_IDLE) {
                log.info("Heartbeat timeout, closing connection: {}", ctx.channel().id());
                ctx.close();
                // 清理用户信息
                UserInfo userInfo = channelInfo.remove(ctx.channel());
                if (userInfo != null) {
                    // 从群组通道映射中移除用户
                    Map<String, Channel> groupChannelMap = groupChannels.get(userInfo.groupId);
                    if (groupChannelMap != null) {
                        groupChannelMap.remove(userInfo.userId);
                        if (groupChannelMap.isEmpty()) {
                            groupChannels.remove(userInfo.groupId);
                        }
                    }

                    // 从在线用户列表中移除
                    Set<String> onlineUsers = groupUsers.get(userInfo.groupId);
                    if (onlineUsers != null) {
                        onlineUsers.remove(userInfo.userId);
                        broadcastOnlineUsers(userInfo.groupId);
                    }
                }
            }
        }
    }*/
    /*@Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            if (e.state() == IdleState.READER_IDLE) {
                log.info("Heartbeat timeout, moving user to offline list: {}", ctx.channel().id());
                UserInfo userInfo = channelInfo.remove(ctx.channel());
                if (userInfo != null) {
                    // 从在线用户列表中移除
                    Set<String> onlineUsers = groupUsers.get(userInfo.groupId);
                    if (onlineUsers != null) {
                        onlineUsers.remove(userInfo.userId);
                        broadcastOnlineUsers(userInfo.groupId); // 广播更新的在线用户列表



                    }

                    // 添加到暂时离线用户列表
                    /*Set<String> offlineUsers = groupOfflineUsers.computeIfAbsent(userInfo.groupId, k -> ConcurrentHashMap.newKeySet());
                    offlineUsers.add(userInfo.userId);
                    broadcastOfflineUsers(userInfo.groupId); // 广播更新的暂时离线用户列表


                }

                // 关闭连接
                ctx.close();
            }
        }
    }*/

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            if (e.state() == IdleState.READER_IDLE) {
                log.info("30s无活动，用户移至暂时离线列表: {}", ctx.channel().id());
                UserInfo userInfo = channelInfo.get(ctx.channel()); // 不remove，保留关联

                /*if (userInfo != null) {
                    // 从在线列表移除
                    Set<String> onlineUsers = groupUsers.get(userInfo.groupId);
                    if (onlineUsers != null) {
                        onlineUsers.remove(userInfo.userId);
                        broadcastOnlineUsers(userInfo.groupId);
                    }

                    // 添加到暂时离线列表
                    Set<String> offlineUsers = groupOfflineUsers.computeIfAbsent(
                            userInfo.groupId, k -> ConcurrentHashMap.newKeySet()
                    );
                    offlineUsers.add(userInfo.userId);
                    broadcastOfflineUsers(userInfo.groupId);
                }
                // 注意：这里不关闭连接，仅更新状态
            }
        }*/
                //4.23新增2
                if (userInfo != null) {
                    // 获取用户加入的所有群组
                    Set<String> userGroups = new HashSet<>();
                    for (Map.Entry<String, Map<String, Channel>> entry : groupChannels.entrySet()) {
                        if (entry.getValue().containsKey(userInfo.userId)) {
                            userGroups.add(entry.getKey());
                        }
                    }

                    // 在所有群组中更新用户状态
                    for (String groupId : userGroups) {
                        // 从在线列表移除
                        Set<String> onlineUsers = groupUsers.get(groupId);
                        if (onlineUsers != null) {
                            onlineUsers.remove(userInfo.userId);
                        }

                        // 添加到暂时离线列表
                        Set<String> offlineUsers = groupOfflineUsers.computeIfAbsent(
                                groupId, k -> ConcurrentHashMap.newKeySet()
                        );
                        offlineUsers.add(userInfo.userId);

                        // 广播状态更新
                        broadcastOnlineUsers(groupId);
                        broadcastOfflineUsers(groupId);
                    }
                }
                // 注意：这里不关闭连接，仅更新状态
            }
        }

    }

    //4.22新增 广播暂时离线用户列表的更新
    private void broadcastOfflineUsers(String groupId) {
        /*try {
            Set<String> offlineUsers = groupOfflineUsers.get(groupId);
            if (offlineUsers != null) {
                Message userListMessage = new Message();
                userListMessage.setFromUser("system");
                userListMessage.setGroupId(groupId);
                userListMessage.setContent("OFFLINE_USERS:" + String.join(",", offlineUsers));
                userListMessage.setTimestamp(System.currentTimeMillis());

                String messageJson = objectMapper.writeValueAsString(userListMessage);
                Map<String, Channel> channels = groupChannels.get(groupId);
                if (channels != null) {
                    channels.values().forEach(channel ->
                            channel.writeAndFlush(new TextWebSocketFrame(messageJson))
                    );
                }
                log.debug("Broadcasted offline users for group {}: {}", groupId, offlineUsers);
            }
        } catch (Exception e) {
            log.error("Error broadcasting offline users for group " + groupId, e);
        }*/
        //4.23修改
        try {
            Set<String> offlineUsers = groupOfflineUsers.getOrDefault(groupId, Collections.emptySet());
            Message userListMessage = new Message();
            userListMessage.setFromUser("system");
            userListMessage.setGroupId(groupId);
            userListMessage.setContent("OFFLINE_USERS:" + String.join(",", offlineUsers));
            userListMessage.setTimestamp(System.currentTimeMillis());

            String messageJson = objectMapper.writeValueAsString(userListMessage);
            Map<String, Channel> channels = groupChannels.get(groupId);
            if (channels != null) {
                channels.values().forEach(channel ->
                        channel.writeAndFlush(new TextWebSocketFrame(messageJson))
                );
            }
            log.debug("Broadcasted offline users for group {}: {}", groupId, offlineUsers);
        } catch (Exception e) {
            log.error("Error broadcasting offline users for group " + groupId, e);
        }
    }

    // 添加心跳发送方法
    private void sendHeartbeat(ChannelHandlerContext ctx) {
        ctx.executor().schedule(() -> {
            if (ctx.channel().isActive()) {
                ctx.writeAndFlush(new TextWebSocketFrame("HEARTBEAT"));
                sendHeartbeat(ctx); // 递归调用，实现定期发送
            }
        }, HEARTBEAT_INTERVAL, TimeUnit.MILLISECONDS);
    }


    /*@Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("Channel Inactive: {}", ctx.channel().id());
        // 同样处理用户离线逻辑
        handlerRemoved(ctx);
        super.channelInactive(ctx);

    }*/
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        /*UserInfo userInfo = channelInfo.remove(ctx.channel());
        if (userInfo != null) {
            // 从所有群组的在线/离线列表中移除
            groupUsers.values().forEach(users -> users.remove(userInfo.userId));
            groupOfflineUsers.values().forEach(users -> users.remove(userInfo.userId));
            // 广播更新所有相关群组
            groupUsers.keySet().forEach(this::broadcastOnlineUsers);
            groupOfflineUsers.keySet().forEach(this::broadcastOfflineUsers);
        }
        super.channelInactive(ctx);
         */
        //4.23新增2
        UserInfo userInfo = channelInfo.remove(ctx.channel());
        if (userInfo != null) {
            // 获取用户加入的所有群组
            Set<String> userGroups = new HashSet<>();
            for (Map.Entry<String, Map<String, Channel>> entry : groupChannels.entrySet()) {
                if (entry.getValue().containsKey(userInfo.userId)) {
                    userGroups.add(entry.getKey());
                }
            }

            // 在所有群组中移除用户
            for (String groupId : userGroups) {
                // 从在线/离线列表中移除
                Set<String> onlineUsers = groupUsers.get(groupId);
                if (onlineUsers != null) {
                    onlineUsers.remove(userInfo.userId);
                }
                Set<String> offlineUsers = groupOfflineUsers.get(groupId);
                if (offlineUsers != null) {
                    offlineUsers.remove(userInfo.userId);
                }

                // 广播更新
                broadcastOnlineUsers(groupId);
                broadcastOfflineUsers(groupId);
            }
        }
        super.channelInactive(ctx);
    }


}